package org.lightweightimageviewer.liv;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static org.lightweightimageviewer.liv.UserPreferences.*;
/**
 * This class is designed to maintain viewer state and cache.
 * @author Steven Boscarine
 *
 */
public class ImageCache {
	private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ImageCache.class);
	/**
	 * Cache of image references indexed by file name.
	 */
	private Map<String, LiImage> cache = new HashMap<String, LiImage>();
	/**
	 * List of files only contains file names.  Need to prepend full directory.
	 */
	private final String directory;
	/**
	 * position of current image.
	 */
	private int index = 0; 
	/**
	 * List of images.  Stored in array for minimum memory usage and maximum lookup performance.
	 */
	private final String[] files;

	public ImageCache(File dir) {
		files = dir.list(ImageFilter.getInstance()); // get list of file names.
		Arrays.sort(files); // sort list in alphabetical order
		//If File reference passed was file, we need to get parent directory reference to cache peers.
		if (!dir.isDirectory()) {
			// find position of argument in alphabetical listing of directory.
			for (; index < files.length; index++) {
				if (files.equals(dir.getPath())) {
					break;
				}
			}
			directory = dir.getParent();
		} else {
			directory = dir.getAbsolutePath();
		}
		refreshForwardCache();
		refreshPrevousCache();
	}

	private synchronized final void refreshForwardCache() {
		final int max = ((index + FETCH_NEXT) > files.length) ? files.length : (index + FETCH_NEXT);
		for(int i = index; i < max; i++){
			addToCache(i);
		}
	}

	private synchronized final void refreshPrevousCache() {
		final int min = ((index - FETCH_PREVIOUS) < 0) ? 0 : (index - FETCH_PREVIOUS);
		for(int i = index; i > min; i--){
			addToCache(i);
		}
	}

	private void addToCache(int i) {
		if(i < 0 || i >= files.length)	return;		//validate index
		final String key = files[i];
		if(!cache.containsKey(key)){
			LiImage value = new LiImage(directory + File.separator + files[i], i);
			cache.put(key, value);
		}
	}
	
	private void removeFromCache(int i){
		if(i < 0 || i >= files.length)	return;		//validate index
		cache.remove(files[i]);
	}
	
	final LiImage getCurrent() {
		final String key = files[index];
		if(!cache.containsKey(key)){
			logger.error("Caching error.  Image " + key + " was requested, but not found in the cache.");
			addToCache(index);
		}
		return cache.get(key);
	}

	final LiImage getNext() {
		if(index < files.length-1){
			index++;	//advance index
			addToCache(index + FETCH_NEXT);			//populate forward cache.
			removeFromCache(index - FETCH_PREVIOUS);//remove entry from backwards cache to conserve memory 
		}
		return getCurrent();
	}

	final LiImage getPrevious() {
		if(index > 0){	
			index--;	//decrement index
			addToCache(index - FETCH_PREVIOUS);		//populate backwards cache.
			removeFromCache(index + FETCH_NEXT);	//remove last entry in forward cache to conserve memory
		}
		return getCurrent();
	}
	
	
	/**
	 * Slideshow algorithm:
	 * 	load next image in background.
	 * 	retrieve current image
	 * 	remove current image.
	 * 	At end of list, start from beginning.
	 * 	NOTE:  This will hose your cache.  
	 * @return
	 */
	final LiImage getNextSlideshowImage(){
		index++;
		if(index == files.length){
			index = 0;	//reset index.
		}
		addToCache(index+1);
		final String key = files[index];
		if(!cache.containsKey(key)){
			logger.error("Caching error.  Image " + key + " was requested, but not found in the cache.");
			return new LiImage(directory + File.separator + files[index], index);
		}
		return cache.remove(key);		
	}
	final int getTotal(){
		return files.length;
	}
}